#ifndef CONFIG_H
#define CONFIG_H

#include <string>
#include <map>
#include <vector>

// Enum definitions
enum class OrbitType {
    Broadcast,
    Precise,
    RealTime
};

enum class TimeSystem {
    Gpst,
    UTC,
    BDT,
    Glonasst
};

enum class CycleSlipMethod {
    None,
    GeometryFree,
    MelbourneWubbena,
    TimeDifference,
    IonosphereRate,
    TurboEdit,
    All
};

enum class WeightingMode {
    Uniform,  
    Elevation,
    Snr,
    Multipath,
    Combined
};

enum class MultipathMitigationStrategy {
    None,
    Smoothing,
    SiderealFiltering,
    Exclusion
};

// Forward declarations
enum class IonoModelType {
    SphericalHarmonic,
    Tomography,
    NeuralNetwork,
    Kriging
};
/**
 * @brief Comprehensive configuration class for the GNSS VTEC estimation system
 * 
 * This class centralizes all configuration settings for the entire processing
 * chain, from data parsing to VTEC modeling and DCB estimation.
 */
class Config {
public:
    // Singleton pattern
    static Config& getInstance();
    
    // General settings
    bool verbose = false;
    int numThreads = 1;
    std::string outputDir = "./output";
    
    // RINEX parsing settings
    struct RinexSettings {
        bool detectVersion = true;
        std::vector<std::string> gnssSystems = {"G", "R", "E", "C", "J"};
        std::map<std::string, std::string> observationCodes = {
            {"G", "C1C,L1C,C2W,L2W"}, // GPS default codes
            {"R", "C1C,L1C,C2C,L2C"}, // GLONASS default codes
            {"E", "C1X,L1X,C5X,L5X"}, // Galileo default codes
            {"C", "C2I,L2I,C7I,L7I"}, // BeiDou default codes
            {"J", "C1C,L1C,C5X,L5X"}  // QZSS default codes
        };
        std::map<std::string, double> defaultL1Frequencies = {
            {"G", 1575.42e6},  // GPS L1
            {"R", 1602.00e6},  // GLONASS L1 (nominal, actual depends on slot)
            {"E", 1575.42e6},  // Galileo E1
            {"C", 1561.098e6}, // BeiDou B1
            {"J", 1575.42e6}   // QZSS L1
        };
        std::map<std::string, double> defaultL2Frequencies = {
            {"G", 1227.60e6},  // GPS L2
            {"R", 1246.00e6},  // GLONASS L2 (nominal)
            {"E", 1176.45e6},  // Galileo E5a
            {"C", 1207.140e6}, // BeiDou B2
            {"J", 1176.45e6}   // QZSS L5
        };
        
        // Multiple file support
        struct FileConfig {
            std::string path;
            std::vector<std::string> enabledSystems; // Empty means use global settings
            bool ignoreFlags = false; // Ignore quality flags in RINEX
        };
        
        std::vector<FileConfig> observationFiles;
        std::vector<FileConfig> navigationFiles;
        std::string sp3File = "";
        
        // File pattern support
        struct FilePatternConfig {
            std::string pattern;  // Pattern with wildcards, e.g. "data/*.24o"
            std::vector<std::string> enabledSystems;
        };
        
        std::vector<FilePatternConfig> observationPatterns;
        std::vector<FilePatternConfig> navigationPatterns;
        std::vector<std::string> sp3Patterns;
        
        // Helper method to add an observation file
        void addObservationFile(const std::string& path, const std::vector<std::string>& systems = {}) {
            FileConfig config;
            config.path = path;
            config.enabledSystems = systems;
            observationFiles.push_back(config);
        }
        
        // Helper method to add a navigation file
        void addNavigationFile(const std::string& path) {
            FileConfig config;
            config.path = path;
            navigationFiles.push_back(config);
        }
        
        // Helper method to add an observation file pattern
        void addObservationPattern(const std::string& pattern, const std::vector<std::string>& systems = {}) {
            FilePatternConfig config;
            config.pattern = pattern;
            config.enabledSystems = systems;
            observationPatterns.push_back(config);
        }
        
        // Helper method to add a navigation file pattern
        void addNavigationPattern(const std::string& pattern) {
            FilePatternConfig config;
            config.pattern = pattern;
            navigationPatterns.push_back(config);
        }
        
        // Helper method to expand patterns to actual files
        void expandFilePatterns();
    } rinexSettings;
    
    // Orbit settings
    struct OrbitSettings {
        OrbitType orbitType = OrbitType::Broadcast;
        std::string sp3File = "";
        bool applyRelativisticCorrection = true;
        bool useIGSPreciseClocks = false;
        TimeSystem timeSystem = TimeSystem::Gpst;
        double interpolationInterval = 900.0; // seconds
        int interpolationDegree = 10;         // Lagrange interpolation degree
    } orbitSettings;
    
    // Preprocessing settings
    struct PreprocessingSettings {
        // Quality control
        double minElevation = 10.0; // degrees
        double minSnr = 10.0;       // dB-Hz
        int minSatelliteCount = 4;  // Minimum satellites per epoch
        
        // Cycle slip detection
        CycleSlipMethod cycleSlipMethod = CycleSlipMethod::GeometryFree;
        
        // Individual cycle slip detection thresholds
        double gfThreshold = 0.25;     // Geometry-free threshold (cycles)
        double mwThreshold = 0.75;     // Melbourne-Wübbena threshold (cycles)
        double tdThreshold = 0.05;     // Time difference threshold (cycles/s)
        double ionoRateThreshold = 0.02; // Ionospheric rate threshold (TECU/s)
        
        // TurboEdit strategy parameters
        enum class TurboEditStrategy {
            Conservative,  // Detect if either GF or MW detects (logical OR)
            Strict,        // Detect only if both GF and MW detect (logical AND)
            Adaptive       // Use AND/OR based on data quality
        };
        
        TurboEditStrategy turboEditStrategy = TurboEditStrategy::Conservative;
        
        // Adaptive TurboEdit parameters (used when strategy is ADAPTIVE)
        double adaptiveQualityThreshold = 0.8;  // Quality level 0-1 for switching between OR/AND
        
        // Cycle slip handling
        bool fixCycleSlips = true;        // Attempt to repair detected cycle slips
        int maxConsecutiveSlips = 5;      // Max consecutive slips before segment rejection
        double maxTimeGap = 300.0;        // Time gap (seconds) automatically causing cycle slip
        
        // Multipath detection and mitigation
        bool enableMultipathDetection = true;
        MultipathMitigationStrategy multipathStrategy = MultipathMitigationStrategy::Smoothing;
        double multipathThreshold = 0.5; // meters
        int smoothingWindow = 5;         // epochs
        
        // Observation weighting
        WeightingMode weightingMode = WeightingMode::Elevation;
        double elevationPower = 2.0;      // Power for elevation-based weighting
        double minWeight = 0.01;          // Minimum observation weight
        double snrScaleFactor = 0.05;     // Scale factor for SNR-based weighting
        double multipathScaleFactor = 3.0; // Scale factor for multipath-based weighting
    } preprocessingSettings;
    
    // STEC calculation settings
    struct STECSettings {
        bool useSmoothedCode = true;
        bool applyPhaseWindup = true;
        bool applyDCBCorrection = false;
        std::string dcbFile = "";      // Optional external DCB file
        double maxSTECValue = 100.0;   // Maximum allowed STEC value in TECU
        double minSTECValue = -20.0;   // Minimum allowed STEC value in TECU
        int smoothingWindowSize = 30;  // 相位对齐伪距水平的滑动窗口大小（观测历元数）
        bool enablePhaseAlignedSTEC = true;  // 是否启用相位对齐伪距水平的STEC计算
        double minArcLength = 5.0;     // 最小弧段长度（分钟）
        bool removeOutliers = true;    // 是否移除异常值
        double outlierThreshold = 3.0; // 异常值识别阈值（标准差倍数）
    } stecSettings;
    
    // VTEC conversion settings
    struct VTECSettings {
        double ionosphereHeight = 450.0; // km
        
        // 映射函数类型选项
        enum class MappingFunctionType {
            SLM,    // 单层模型 (默认)
            MSLM,   // 修正单层模型
            TSM     // 薄壳映射函数
        };
        
        MappingFunctionType mappingFunctionType = MappingFunctionType::SLM;
        std::string mappingFunction = "SLM"; // 兼容旧接口，"SLM", "MSLM", "TSM"
        
        // 水平梯度支持
        bool applyAzimuthalAsymmetry = false;   // 是否考虑方位角非对称性
        double latitudeGradient = 0.0;          // 纬度方向梯度
        double longitudeGradient = 0.0;         // 经度方向梯度
        
        // 方位角加权
        bool useAzimuthalWeighting = false;     // 是否使用方位角加权
        double northWeight = 1.0;               // 北方向权重
        double eastWeight = 1.0;                // 东方向权重
        double southWeight = 1.0;               // 南方向权重
        double westWeight = 1.0;                // 西方向权重
        
        double latitudeCutoff = 80.0;           // 纬度截断值(度)
        
        // 便捷方法设置映射函数类型
        void setMappingFunctionType(const std::string& mapFunc) {
            mappingFunction = mapFunc;
            if (mapFunc == "MSLM") {
                mappingFunctionType = MappingFunctionType::MSLM;
            } else if (mapFunc == "TSM") {
                mappingFunctionType = MappingFunctionType::TSM;
            } else {
                mappingFunctionType = MappingFunctionType::SLM;
            }
        }
    } vtecSettings;
    
    // Spherical harmonic modeling settings
    struct SphericalHarmonicSettings {
        int maxDegree = 8;
        int maxOrder = 8;
        bool useTemporal = true;
        int temporalDegree = 2;
        bool regularization = true;
        double regularizationFactor = 0.001;
        bool useKalmanFilter = false;
        double processNoise = 1e-7;
        bool constrainNighttime = true;
    } sphericalHarmonicSettings;
    
    // DCB estimation settings
    struct DCBSettings {
        bool estimateSatelliteDCB = true;
        bool estimateReceiverDCB = true;
        bool constrainZeroMean = true;
        bool useExternalDCB = false;
        std::string externalDCBFile = "";
        double satDCBStdThreshold = 3.0; // ns
        double recDCBStdThreshold = 5.0; // ns
    } dcbSettings;
    
    // IONEX output settings
    struct IONEXSettings {
        double gridLongitudeResolution = 5.0; // degrees
        double gridLatitudeResolution = 2.5;  // degrees
        int temporalResolution = 2;           // hours
        bool outputSatelliteDCB = true;
        bool outputReceiverDCB = true;
        bool outputRMS = true;
        int ionexVersion = 1;
        std::string outputFile = "output.ionex";
    } ionexSettings;
    
    // Load/save configuration
    bool loadFromFile(const std::string& filename);
    bool saveToFile(const std::string& filename) const;
    void printConfig() const;
    
    // Command line parsing
    bool parseCommandLine(int argc, char* argv[]);
    
private:
    // Private constructor for singleton
    Config() = default;
    
    // Prevent copying
    Config(const Config&) = delete;
    Config& operator=(const Config&) = delete;
};

#endif // CONFIG_H 